package _1_1_Basic;

import org.junit.Test;

import javax.xml.bind.DatatypeConverter;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;

public class _3_AboutString {

    /**
     * String 的值以 char[] 存储，这个char[] 的 char以 Unicode编码保存在内存中
     */
    @Test
    public void unicode() throws UnsupportedEncodingException {

        String a = "I love 敏敏";
        // 此时，内存中存储的是 char[], 每一个char都是utf-16编码

        byte[] bytes = a.getBytes("GB2312");
        // 使用getBytes()方法按指定编码把 char[] 转为 byte[] 用于传输
        // 此时 byte[] 的编码格式是指定的 GB2312 编码



        String gbk = new String(bytes, "GBK");
        // 这里可以正常把 byte[] 转为 char[] , 因为指定的编码格式可以用
        System.out.println(gbk);

        String x1 = new String(bytes, "ISO8859-1");
        // 这里会乱码，因为上面有中文，byte[] 的编码是 GB2312,
        // byte[] 转 char[]时, 不适用的编码会造成字符串乱码
        System.out.println(x1);

        // http header中必须是ASCII字符, 要用 URLEncoder.encode 进行转码
        String encode = URLEncoder.encode(a, "utf-8");
        System.out.println(encode);

        String str = "\u005B\u00A0\u005D";
        System.out.println(str);

        System.out.println("\u4e0d\u80fd\u4e3a\u7a7a");

        System.out.println("希腊字母\u03B1\u03CB\u03CC");


        byte[] bytes2 = "中文3".getBytes("utf-8");
        for (byte b : bytes2) {
            int v = (int) b;
            String s = Integer.toBinaryString(v);
            System.out.println(("00000000" + s).substring(s.length()));
        }
        str = new String(bytes2, "utf-8");
        System.out.println(str);


        for (int i = 0; i < str.length(); i++) {
            char c = str.charAt(i);
            int v = (int) c;
            System.out.println(v);
            String s = Integer.toBinaryString(v);
            String x = "00000000" + s;
            System.out.println(x.substring(s.length()));
        }

        // \u0022 就是 " 号, \u0022 先转为 " , 然后变成 ""+""
        // 而不是先 执行 +
        System.out.println("\u0022+\u0022");

        // 转义字符
        // \u00A0 is a newline
    }


    /**
     * 运行速度: StringBuilder > StringBuffer > String
     *    原因: String{@link String} 是字符串常量,创建后不能实质更改(见String类头部注释),
     *          所以对String的操作, 实际上是 jvm创建了另一个新的 String对象, 并回收旧对象
     *          StringBuilder {@link StringBuilder} 字符串变量, 非线程安全, 详见注释
     *          StringBuffer  {@link StringBuffer} 字符串变量, 线程安全, 详见注释
     * 因此:
     *     String：       适用于 少量的字符串操作
     *     StringBuilder：适用于 单线程 下在字符缓冲区进行大量操作, 例如: sql语句的拼接上
     *     StringBuffer： 适用于 多线程 下在字符缓冲区进行大量操作
     */
    @Test
    public void compareStringBuilderBuffer(){

        // 测试速度：10000次循环
        long time1 = System.currentTimeMillis();

        String str = "abc";
        for (int i = 0; i < 20000; i++)
            str = str + "def";
        long time2 = System.currentTimeMillis();


        for (int i = 0; i < 20000; i++)
            str = str.concat("def");
        long time3 = System.currentTimeMillis();


        StringBuilder stringBuilder = new StringBuilder().append("abc");
        for (int i = 0; i < 20000; i++)
            stringBuilder.append("def");
        long time4 = System.currentTimeMillis();

        System.out.println(time2 - time1);      // String + String
        System.out.println(time3 - time2);      // String.concat(String)
        System.out.println(time4 - time3);      // StringBuilder.append
    }

    /**
     * 字符格式化技巧
     */
    @Test
    public void methodOfString() {
        // String 字符前补0， 格式化
        String substring = ("00000000" + "Apple").substring("Apple".length());
        System.out.println(substring);

        String s = String.format("%02d", 1000);
        System.out.println(s);
    }

    @Test
    public void hexStringToBytes() {
        long start = System.currentTimeMillis();
        // 使用 自己写的的方法
        for (int i = 0; i < 50000; i++) {
            hexStringToByteArray("0c01186401010600060050040c01186401010600060050040c01186401010600060050040c01186401010600060050040c01186401010600060050040c01186401010600060050040c01186401010600060050040c0118640101060006005004");
        }
        long end1 = System.currentTimeMillis();

        // 使用 java 原生库带的方法
        for (int i = 0; i < 50000; i++) {
            DatatypeConverter.parseHexBinary("0c01186401010600060050040c01186401010600060050040c01186401010600060050040c01186401010600060050040c01186401010600060050040c01186401010600060050040c01186401010600060050040c0118640101060006005004");
        }

        long end2 = System.currentTimeMillis();
        System.out.println(end1 - start);
        System.out.println(end2 - end1);

    }

    public static byte[] hexStringToByteArray(String s) {
        int len = s.length();
        byte[] data = new byte[len / 2];
        for (int i = 0; i < len; i += 2) {
            data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
                + Character.digit(s.charAt(i+1), 16));
        }
        return data;
    }
}
